package com.ejlchina.tool.base

import android.Manifest
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothManager
import android.content.pm.PackageManager
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.view.*
import android.view.animation.LinearInterpolator
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.viewbinding.ViewBinding
import com.adolf.androiddemo.R
import com.adolf.androiddemo.databinding.FragmentBaseBinding
import com.ejlchina.tool.MainActivity
import com.ejlchina.tool.adapter.DeviceAdapterRadio
import com.ejlchina.tool.adapter.DeviceAdapterRadioOffline
import com.ejlchina.tool.adapter.DeviceHeadAdapterMulti
import com.ejlchina.tool.adapter.DeviceHeadAdapterRadio
import com.ejlchina.tool.bean.BleDeviceBean
import com.ejlchina.tool.constant.DEVICE_MODE_NO_SELECT
import com.ejlchina.tool.constant.DEVICE_MODE_ONLINE
import com.ejlchina.tool.constant.SP_DEVICE_MODE
import com.ejlchina.tool.enums.SuccessFailEnum
import com.ejlchina.tool.extension.safeNavigate
import com.ejlchina.tool.singleton.GlobalAction
import com.ejlchina.tool.singleton.GlobalConnectObject
import com.ejlchina.tool.singleton.GlobalParams
import com.ejlchina.tool.singleton.SharedPreferenceUtil
import com.ejlchina.tool.util.COMMAND_TOKEN_UPWARD
import com.ejlchina.tool.util.LOG_TAG
import com.ejlchina.tool.util.bytearray.toHexString
import com.ejlchina.tool.util.getDownwardCommand
import com.ejlchina.tool.util.getUpwardData
import com.ejlchina.tool.util.paddingByStatusBar
import com.ejlchina.tool.util.showToast
import com.ejlchina.tool.viewmodel.MainViewModel
import com.ejlchina.tool.viewmodel.PRIORITY_WRITE_DEFAULT
import com.huyuhui.fastble.BleManager
import com.huyuhui.fastble.data.BleDevice
import kotlinx.coroutines.launch


abstract class BaseBindingFragment2<VB : ViewBinding>: Fragment(){

    private var _baseBinding: FragmentBaseBinding? = null
    private val baseBinding
        get() = _baseBinding!!

    private var _binding: VB? = null
    protected val binding: VB
        get() = _binding!!


    private var objectAnimator: ObjectAnimator? = null

    protected val viewModelActivity :MainViewModel by activityViewModels()
    protected val deviceListBase = mutableListOf<BleDeviceBean>()
    protected lateinit var deviceHeadAdapter: DeviceHeadAdapterRadio
    protected lateinit var deviceAdapter: DeviceAdapterRadio
    protected lateinit var deviceAdapterOffline: DeviceAdapterRadioOffline
    protected lateinit var deviceListHeadAdapterMulti: DeviceHeadAdapterMulti

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        printNameForSubclass()
    }
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        _baseBinding = FragmentBaseBinding.inflate(inflater, container, false)
        _binding = getViewBinding(inflater, baseBinding.fragmentContent)
        initOnCreateView()
        setRightIconVisibility(View.GONE)
        setLeftIconAction{navigationUp()}
        return baseBinding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initConnectDeviceList()
        initObservers()
    }



    protected fun deleteAllDisconnectDevice(){
        //这个判断是用来对应一个情况：几个设备同时固件升级，成功后会断开设备，但是同时发flow的时候好像没有完全处理
        if (viewModelActivity.getAllConnectDevicesCount() == 0){
            GlobalConnectObject.getCurrentConnectDeviceList().clear()
        } else {
            GlobalConnectObject.getCurrentConnectDeviceList().removeIf {localConnectBean ->
                !viewModelActivity.getAllConnectDevices().map { it.mac }.contains(localConnectBean.bleDevice.mac)
            }
        }
    }

    private fun printNameForSubclass(){
        Log.i(LOG_TAG,javaClass.simpleName)
    }


    private fun initConnectDeviceList() {
        GlobalConnectObject.resetSelectState()
    }

    private fun transformDeviceBean(): MutableList<BleDeviceBean>{
        val resultList = mutableListOf<BleDeviceBean>()
        val connectDeviceList = viewModelActivity.getAllConnectDevices()
        for (item in connectDeviceList){
            val bleDeviceBean = BleDeviceBean(
                bleDevice = item,
                version = GlobalParams.connectDeviceVersionList.find { it.mac == item.mac }?.firmwareVersion ?: "",
                hardVersion = GlobalParams.connectDeviceVersionList.find { it.mac == item.mac }?.hardVersion ?: ""
            )
            resultList.add(bleDeviceBean)
        }
        return resultList
    }


    fun setHeadTitle(title: String){
        setHeadVisibility(View.VISIBLE)
        baseBinding.baseTitleText.text = title
        baseBinding.baseTitleText.paint.isFakeBoldText = true
        setLeftIconVisibility(View.VISIBLE)
    }

    fun setRightTextAndAction(title: String, action: (() -> Unit)? = null){
        setHeadVisibility(View.VISIBLE)
        baseBinding.baseRightText.visibility = View.VISIBLE
        baseBinding.baseRightText.apply {
            text = title
            setOnClickListener { action?.invoke() }
        }
    }

    fun setLeftIconVisibility(visibility: Int){
        baseBinding.baseCloseLeftImg.visibility = visibility
    }

    fun setRightIconVisibility(visibility: Int){
        setHeadVisibility(View.VISIBLE)
        baseBinding.baseCloseRightImg.visibility = visibility
    }

    fun setRightIconAction(action: (() -> Unit)?){
        baseBinding.baseCloseRightImg.setOnClickListener {
            action?.invoke()
        }
    }

    fun setRightIconImage(resId: Int){
        baseBinding.baseCloseRightImg.setImageResource(resId)
    }

    fun setHeadVisibility(visibility: Int){
        baseBinding.layoutHeader.visibility = visibility
    }


    fun setHeadBackground(color: Int){
        setHeadVisibility(View.VISIBLE)
        baseBinding.layoutHeader.setBackgroundColor(color)
    }

    fun setLeftIconAction(action: (() -> Unit)?){
        baseBinding.baseCloseLeftImg.setOnClickListener {
            action?.invoke()
        }
    }

    private fun navigationUp(){
        findNavController().popBackStack()
    }

    fun startRotateRightIcon(){
        objectAnimator = ObjectAnimator.ofFloat(baseBinding.baseCloseRightImg,"rotation",0f,359f)
        objectAnimator?.let {
            it.repeatCount = ValueAnimator.INFINITE
            it.duration = 1000
            it.interpolator = LinearInterpolator()
            it.start()
        }
    }

    fun stopRotateIcon(){
        if (objectAnimator?.isRunning == true){
            objectAnimator?.cancel()
        }
    }

    fun setResultToast(result: Int){
        val resultString = if (result == SuccessFailEnum.SUCCESS.value) "设置成功" else "设置失败"
        showToast(resultString)
    }


    @SuppressLint("NotifyDataSetChanged", "MissingPermission")
    private fun initObservers(){
        lifecycleScope.launch {
            launch {
                GlobalAction.disConnectFlow.collect{ disConnectDevice ->
                    GlobalConnectObject.removeDevice(disConnectDevice)
                    BleManager.clearQueue(disConnectDevice)
                    refreshAdapters()

                    if (viewModelActivity.getAllConnectDevicesCount() == 0 &&
                        findNavController().currentDestination?.id != R.id.noDeviceFragment &&
                        findNavController().currentDestination?.id != R.id.scanFragment &&
                        findNavController().currentDestination?.id != R.id.selectDeviceModeFragment &&
                        findNavController().currentDestination?.id != R.id.noDeviceOfflineFragment &&
                        findNavController().currentDestination?.id != R.id.scanOfflineFragment){
                        dismissLoading()
                        if (checkDeviceMode() == DEVICE_MODE_ONLINE){
                            findNavController().safeNavigate(R.id.action_global_no_device)
                        } else {
                            findNavController().safeNavigate(R.id.action_global_no_device_offline)
                        }
                    } else {
                        whenDeviceDisConnect(disConnectDevice)
                    }
                }
            }

            launch {
                GlobalAction.notifyDataFlow.collect{ indicatorResultBean ->
                    if (lifecycle.currentState >= Lifecycle.State.RESUMED) {
                        handleResultCommand(indicatorResultBean.bleDevice, indicatorResultBean.resultData)
                    }
                }
            }

            launch {
                GlobalAction.connectSuccessFlow.collect{
                    BleManager.getBluetoothGatt(it.bleDevice)?.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER)
                    if (isAdded){
                        whenConnectSuccess(it)
                    }
                }
            }
        }
    }

    private fun handleResultCommand(bleDevice: BleDeviceBean, commandByteArray: ByteArray){
        val resultDataString = commandByteArray.toHexString(false)
        val offset = if (resultDataString.startsWith(COMMAND_TOKEN_UPWARD)) 0 else 1
        val dataByteArray = getUpwardData(commandByteArray,offset)
        val subStringEndIndex =  if (resultDataString.startsWith(COMMAND_TOKEN_UPWARD)) 6 else 8
        val commandString = resultDataString.substring(0,subStringEndIndex)
        if (isAdded){
            whenReceiveCommand(bleDevice, commandString,dataByteArray)
        }
    }

    open fun whenDeviceDisConnect(disConnectDevice: BleDevice){

    }
    open fun whenReceiveCommand(bleDevice: BleDeviceBean, command: String, dataByteArray: ByteArray){}

    open fun whenConnectSuccess(bleDeviceBean: BleDeviceBean){}

    protected open fun isAndroid12() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S

    protected open fun hasAccessFineLocation() =
        hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)

    protected open fun hasCoarseLocation() =
        hasPermission(Manifest.permission.ACCESS_COARSE_LOCATION)

    @RequiresApi(Build.VERSION_CODES.S)
    protected open fun hasBluetoothConnect() = hasPermission(Manifest.permission.BLUETOOTH_CONNECT)

    @RequiresApi(Build.VERSION_CODES.S)
    protected open fun hasBluetoothScan() = hasPermission(Manifest.permission.BLUETOOTH_SCAN)

    /**
     * 检查是有拥有某权限
     *
     * @param permission 权限名称
     * @return true 有  false 没有
     */
    protected open fun hasPermission(permission: String) = requireActivity().checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED

    /**
     * 蓝牙是否打开
     *
     * @return true or false
     */
    protected open fun isOpenBluetooth(): Boolean {
        (requireActivity().getSystemService(AppCompatActivity.BLUETOOTH_SERVICE) as BluetoothManager).also {
            it.adapter ?: return false
            return it.adapter.isEnabled
        }
    }

    /**
     * 位置是否打开
     */
    protected open fun isOpenLocation(): Boolean {
        val locationManager = requireActivity().getSystemService(AppCompatActivity.LOCATION_SERVICE) as LocationManager
        val gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
        val network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
        val locationEnabled = isLocationEnabled()
        Log.d("TAG", "gps: $gps，network：$network，locationEnabled：$locationEnabled")
        return gps || network || locationEnabled
    }

    open fun isLocationEnabled(): Boolean {
        val locationMode = try {
            Settings.Secure.getInt(requireActivity().contentResolver, Settings.Secure.LOCATION_MODE)
        } catch (e: Settings.SettingNotFoundException) {
            e.printStackTrace()
            return false
        }
        return locationMode != Settings.Secure.LOCATION_MODE_OFF
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _baseBinding = null
        _binding = null
        Log.i(LOG_TAG, "onDestoryView--${javaClass.simpleName}-${GlobalConnectObject.getCurrentConnectDeviceList().size}")
    }

    fun setActionBarPadding(isNeedPadding: Boolean){
        paddingByStatusBar(baseBinding.root,isNeedPadding)
    }


    protected open fun initOnCreateView(){
        setActionBarPadding(true)
    }

    override fun onResume() {
        super.onResume()
        Log.i(LOG_TAG,"deviceBaseList ---- ${javaClass.simpleName}---$deviceListBase")

        if (viewModelActivity.getAllConnectDevicesCount() == 0 &&
            findNavController().currentDestination?.id != R.id.noDeviceFragment &&
            findNavController().currentDestination?.id != R.id.scanFragment &&
            findNavController().currentDestination?.id != R.id.selectDeviceModeFragment &&
            findNavController().currentDestination?.id != R.id.noDeviceOfflineFragment &&
            findNavController().currentDestination?.id != R.id.scanOfflineFragment){
            dismissLoading()
            if (checkDeviceMode() == DEVICE_MODE_ONLINE){
                findNavController().safeNavigate(R.id.action_global_no_device)
            } else {
                findNavController().safeNavigate(R.id.action_global_no_device_offline)
            }
        }
        deleteAllDisconnectDevice()

    }

    private fun refreshAdapters(){
        if (this@BaseBindingFragment2::deviceHeadAdapter.isInitialized){
            deviceHeadAdapter.notifyDataSetChanged()
        }
        if (this@BaseBindingFragment2::deviceAdapter.isInitialized){
            deviceAdapter.notifyDataSetChanged()
        }
        if (this@BaseBindingFragment2::deviceAdapterOffline.isInitialized){
            deviceAdapterOffline.notifyDataSetChanged()
        }
        if (this@BaseBindingFragment2::deviceListHeadAdapterMulti.isInitialized){
            deviceListHeadAdapterMulti.notifyDataSetChanged()
        }
    }

    fun showLoading(){
        (requireActivity() as MainActivity).showLoading()
    }

    fun dismissLoading(){
        (requireActivity() as MainActivity).dismissLoading()
    }

    fun checkDeviceMode(): Int{
        return SharedPreferenceUtil.getInt(SP_DEVICE_MODE, DEVICE_MODE_NO_SELECT)
    }

    fun getCommandData(bleDevice: BleDeviceBean, command: String, commandVariable: String = "",isAddToHead: Boolean = false, priority: Int = PRIORITY_WRITE_DEFAULT, isShowLoading: Boolean = true,writeType: Int = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) {
        if (isShowLoading) showLoading()
        viewModelActivity.writeByQueue(bleDevice,getDownwardCommand(bleDevice, command, commandVariable), continuous = false,
            isForFileUpload = false,
            priority = priority,
            writeType = writeType)
    }

    fun setCommandData(bleDevice: BleDeviceBean, command: String, commandVariable: String,isAddToHead: Boolean = false, priority: Int = PRIORITY_WRITE_DEFAULT,writeType: Int = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) {
        showLoading()
        viewModelActivity.writeByQueue(bleDevice,getDownwardCommand(bleDevice, command, commandVariable),
            continuous = false,
            isForFileUpload = false,
            priority = priority,
            writeType = writeType)
    }
    protected abstract fun getViewBinding(inflater: LayoutInflater, container: ViewGroup): VB
}